﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Diagnostics;
using HtmlAgilityPack;
using System.Text.RegularExpressions;


// HTML Agility Pack: Install-Package HtmlAgilityPack
// TODO: Sacar las cosas hardcodeadas
//       Agregar diccionario custom para correccion
//       Agregar excepciones a los splits(".") de reuniones
//       Cambiar la conversion espantosa que hago de fechas
//       Foto

// Changelog
// 2017-03-20: Se modifico la busqueda de tramites parlamentarios de diputados para que el programa no pinche cuando el pasante se olvida el titulo :/
// 2017-03-20: Se modifico la busqueda de tramites parlamentarios de diputados para tener en cuenta algunos errores en la carga de los representantes  
// 2017-03-20: Se agrego la busqueda de reuniones de comisiones de diputados. 
// 2017-03-21: Se agrego la busqueda de tramites parlamentarios de Senadores.
// 2017-03-21: Odio a los pasantes de la camara de diputados que no pueden cargar dos paginas con el mismo formato... 
// 2017-03-27: Se agrego el chequeo de genero de los representantes de ambas camaras.
// 2017-03-27: Se cambio todo el formato de salida a HTML para que los links se exporten correctamente.

namespace Actividad_Parlamentaria {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        // Clase para recopilar los proyectos
        private class CLS_DATA {
            public string Representantes { get; set; }
            public string Tipo { get; set; }
            public string Texto { get; set; }
            public string Link { get; set; }
            public string Tags { get; set; }
            public DateTime Fecha { get; set; }
            public bool EsMujer { get; set; }
        }

        // Lista de proyectos de Diputados
        private List<CLS_DATA> ListaDipProyectos = new List<CLS_DATA>();
        private List<CLS_DATA> ListaDipComisiones = new List<CLS_DATA>();
        private List<CLS_DATA> ListaSenProyectos = new List<CLS_DATA>();

        List<string> Mujeres = new List<string>();

        string C_PROXY = "";

        // Tipos de proyectos - DIPUTADOS
        const string C_DIP_PROYECTO_LEY = "DE LEY";
        const string C_DIP_PROYECTO_REPRODUCCION = "REPRODUCE EL";
        const string C_DIP_PROYECTO_RESOLUCION = "DE RESOLUCION";
        const string C_DIP_PROYECTO_COMUNICACION = "DE COMUNICACION";
        const string C_DIP_PROYECTO_DECLARACION = "DE DECLARACION";

        // Tipos de proyectos - SENADORES
        const string C_SEN_PROYECTO_LEY = "PROYECTO DE LEY";
        const string C_SEN_PROYECTO_REPRODUCCION = "REPRODUCE EL";
        const string C_SEN_PROYECTO_RESOLUCION = "PROYECTO DE RESOLUCION";
        const string C_SEN_PROYECTO_COMUNICACION = "PROYECTO DE COMUNICACION";
        const string C_SEN_PROYECTO_DECLARACION = "PROYECTO DE DECLARACION";

        // URLs - DIPUTADOS
        const string C_DIP_URLINISLASH = "http://www.hcdn.gob.ar/";
        const string C_DIP_URLINI = "http://www.hcdn.gob.ar";
        const string C_DIP_URLMID = "proyectos/proyectoTP.jsp?exp=";
        const string C_DIP_URLSEARCH = "hcdn.gob.ar";

        // Headers y footers entre donde se encuentra la info
        const string C_DIP_HEADER1 = "<strong>Proyectos de ley, resoluc";
        const string C_DIP_HEADER2 = ">DIPUTADOS</h3>";
        const string C_DIP_HEADER3 = "<!-- The text content of the paragraph -->";
        const string C_DIP_FOOTER1 = "<!-- The optional links for a paragraph -->";
        const string C_DIP_FOOTER2 = "Solicitudes relacionadas con proyectos de ley, resolución o declaración:</strong></p>";

        // Separadores de campos y otros - DIPUTADOS
        const string C_DIP_TOKEN1 = "</STRONG>";
        const string C_DIP_TOKEN2 = ":";
        const string C_DIP_TOKEN3 = ".";
        const string C_DIP_TOKEN4 = "(";
        const string C_DIP_TOKEN5 = "<A";
        const string C_DIP_TOKEN6 = "HCDN.GOB.AR";
        const string C_DIP_TOKEN6Bis = "HCDN.GOV.AR"; // El pasante que carga los datos es un hdp
        const string C_DIP_TOKEN7 = "\"/";
        const string C_DIP_TOKEN8 = "\"";
        const string C_DIP_TOKEN9 = "<STRONG>";
        const string C_DIP_REGEX1 = "\\d{4}-[a-z]-\\d{4}";
        const string C_DIP_REGEX2 = "\\(\\d{4}-[A-Z]-\\d{4}.*";

        // Separadores de los nombres
        const string C_DIP_SEPNOMBRE1 = "; ";
        const string C_DIP_SEPNOMBRE2 = " Y ";
        const string C_DIP_SEPNOMBRE3 = " E ";
        const string C_DIP_SEPNOMBRE4 = " y ";

        // Separadores de campos y otros - COMUNICACIONES
        const string C_COM_TITLE = "REUNIONES DEL DIA ";
        const string C_COM_TOKEN1 = "<a";
        const string C_COM_TOKEN2 = "<br/>";
        const string C_COM_TOKEN3 = "<br>";
        const string C_COM_SEARCH1 = "comisiones:";
        const string C_COM_SEARCH2 = "comision:";
        readonly string[] C_COM_WORDS1 = { "De ", "La ", "Y ", "Del ", "E " };


        readonly string[] C_COM_WORDS2 = { "Sr.", "Sra.", "H.", "Lic.", "Dr." }; //****** En archivo de configuracion

        // Separadores de campos y otros - SENADORES
        const string C_SEN_TOKEN1 = "<a";
        const string C_SEN_TOKEN2 = "<li>";
        const string C_SEN_TOKEN3 = "<img";
        const string C_SEN_TOKEN4 = "PROYECTO DE LEY";
        const string C_SEN_TOKEN5 = ": ";
        const string C_SEN_TOKEN6_class = "font-size:1.6em; border-right-color: #fff;";
        const string C_SEN_REGEX = "\\d{2}-\\d{2}-\\d{4}";

        // URLs - SENADORES
        const string C_SEN_URLINI = "http://www.senado.gov.ar";
        const string C_SEN_URLEND = "/proyectos?page=#NRO#";

        // Templates para mostrar la info
        const string C_TEMPLATE_SIMPLE = "<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES# <a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</p>\r\n";
        const string C_TEMPLATE_MULTIPLE = "<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES#</p>\r\n<ul>\r\n#LIDATA#</ul>\r\n";
        const string C_TEMPLATE_MULTIPLE_LINEA = "<li style=\"text-align:justify;\"><a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</li>\r\n";

        // Carga inicial
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            // Proxy
            if (System.IO.File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "proxy.txt")) {
                using (System.IO.StreamReader Reader = new System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory + "proxy.txt")) {
                    C_PROXY = Reader.ReadToEnd();
                }
            }

            // Genero
            if (System.IO.File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "mujeres.txt")) {
                using (System.IO.StreamReader Reader = new System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory + "mujeres.txt")) {
                    string Contenido = Reader.ReadToEnd();
                    Mujeres = Contenido.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
                }
            }
        }

        // Busca los tramites parlamentarios de diputados
        private async void btnDipBuscarTramites_Click(object sender, RoutedEventArgs e) {
            SetControls(false);

            // Opciones
            if (!OptionsOK()) return;

            LogLine("Cargando el sitio " + txtDipUrlTramites.Text);
            string strTramites = await GetWeb(txtDipUrlTramites.Text);

            if (!string.IsNullOrEmpty(strTramites)) {
                LogLine("Sitio cargado. Buscando tramites parlamentarios de diputados en el rango de fechas [" +
                    dtpFechaDesde.SelectedDate.Value.ToString("dd-MM-yyyy") + " - " +
                    dtpFechaHasta.SelectedDate.Value.ToString("dd-MM-yyyy") + "]");

                HtmlAgilityPack.HtmlDocument objDoc = new HtmlAgilityPack.HtmlDocument();
                objDoc.LoadHtml(strTramites);

                if (objDoc.DocumentNode != null) {
                    // Tablas - Hay una sola, es la que me interesa :D
                    HtmlNodeCollection Tables = objDoc.DocumentNode.SelectNodes("//table");
                    HtmlNode TableTramites = Tables[0];

                    // Los tramites
                    ListaDipProyectos.Clear();
                    HtmlNodeCollection NodeRows = TableTramites.SelectNodes(".//tr");
                    NodeRows.RemoveAt(0); // Saco los headers
                    foreach (HtmlNode NodeR in NodeRows) {
                        HtmlNodeCollection NodeColumns = NodeR.SelectNodes(".//td");
                        string[] strFechaTramite = NodeColumns[1].InnerText.Split('-');
                        DateTime FechaTramite = new DateTime(int.Parse(strFechaTramite[2]), int.Parse(strFechaTramite[1]), int.Parse(strFechaTramite[0]));

                        if (FechaTramite.Ticks >= dtpFechaDesde.SelectedDate.Value.Ticks && FechaTramite.Ticks <= dtpFechaHasta.SelectedDate.Value.Ticks) {
                            HtmlNode SingleNode = NodeColumns[0].SelectSingleNode(".//a");
                            string strURLProyectos = C_DIP_URLINISLASH + SingleNode.Attributes["href"].Value;
                            List<CLS_DATA> ListaTemp = new List<CLS_DATA>();
                            ListaTemp = await BuscarDipProyectos(strURLProyectos);
                            if (ListaTemp.Count > 0) ListaDipProyectos.AddRange(ListaTemp);
                        }
                    }
                }
                else {
                    LogLine("[ERROR] [btnDipTramitesBuscar_Click]: objDoc.DocumentNode == null");
                }
                LogLine("Busqueda de tramites parlamentarios de diputados finalizada!");
            }
            else {
                LogLine("Hubo un error cargando el sitio. Reintente nuevamente.");
            }
            SetControls();
        }

        // Busca los proyectos de diputados en la pagina de cada fecha
        private async Task<List<CLS_DATA>> BuscarDipProyectos(string urlProyectos) {
            List<CLS_DATA> ListaTemp = new List<CLS_DATA>();
            LogLine("Cargando el sitio " + urlProyectos);
            string strProyectos = await GetWeb(urlProyectos);

            if (!string.IsNullOrEmpty(strProyectos)) {
                LogLine("Pagina cargada. Buscando tramites...");
                if (strProyectos.Contains(C_DIP_HEADER1)) {
                    strProyectos = strProyectos.Substring(strProyectos.IndexOf(C_DIP_HEADER1));
                }
                else { // Si el pasante se olvido el titulo :S
                    strProyectos = strProyectos.Substring(strProyectos.IndexOf(C_DIP_HEADER2));
                }

                strProyectos = strProyectos.Substring(0, strProyectos.IndexOf(C_DIP_FOOTER1));
                if (strProyectos.Contains(C_DIP_FOOTER2)) {
                    strProyectos = strProyectos.Substring(0, strProyectos.IndexOf(C_DIP_FOOTER2));
                }
                strProyectos = strProyectos.Replace("<p style=\"text-align: justify;\"><strong>", "");
                strProyectos = strProyectos.Replace("\r", "");
                strProyectos = strProyectos.Replace("\n", "");

                // Como odio al sorete que carga estos proyectos...
                List<string> tempListaProyectos = new List<string>();
                if (strProyectos.ToUpper().Contains("<BR />"))
                   tempListaProyectos = strProyectos.ToUpper().Split(new string[] { "<BR />" }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
                else
                    tempListaProyectos = strProyectos.ToUpper().Split(new string[] { "</P>" }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();

                tempListaProyectos.RemoveAt(0); // saco el titulo

                bool Procesar = false;
                foreach (string Proyecto in tempListaProyectos) {
                    CLS_DATA InfoProyecto = new CLS_DATA();
                    Procesar = false;

                    InfoProyecto.Tipo = BuscarCampoTipo(Proyecto);
                    if (chkProyectoComunicacion.IsChecked.Value && InfoProyecto.Tipo == C_DIP_PROYECTO_COMUNICACION) Procesar = true;
                    if (chkProyectoDeclaracion.IsChecked.Value && InfoProyecto.Tipo == C_DIP_PROYECTO_DECLARACION) Procesar = true;
                    if (chkProyectoReproduccion.IsChecked.Value && InfoProyecto.Tipo == C_DIP_PROYECTO_REPRODUCCION) Procesar = true;
                    if (chkProyectoResolucion.IsChecked.Value && InfoProyecto.Tipo == C_DIP_PROYECTO_RESOLUCION) Procesar = true;
                    if (chkProyectoLey.IsChecked.Value && InfoProyecto.Tipo == C_DIP_PROYECTO_LEY) Procesar = true;

                    if (Procesar) {
                        InfoProyecto.EsMujer = true;
                        InfoProyecto.Representantes = BuscarCampoRepresentantes(Proyecto);
                        InfoProyecto.Texto = BuscarCampoTexto(Proyecto);
                        InfoProyecto.Tipo = InfoProyecto.Tipo.ToLower().Replace("cion","ción"); //hue
                        InfoProyecto.Link = BuscarCampoLink(Proyecto);
                        InfoProyecto.Tags = BuscarCampoTags(Proyecto);
                        ListaTemp.Add(InfoProyecto);
                    }
                }
            }
            else {
                LogLine("[ERROR] [BuscarProyectos]: El sitio esta en blanco WTF");
            }

            return ListaTemp;
        }

        // Busqueda de campos
        private string BuscarCampoRepresentantes(string Proyecto) {
            string result = Proyecto;

            // Corto en el primer ":"
            if (result.Contains(C_DIP_TOKEN2))
                result = result.Substring(0, result.IndexOf(C_DIP_TOKEN2)).Trim();
            //else
            //**** Ver que onda si no hay ":"

            // Saco todo lo que sea tag HTML
            result = StripHTMLTags(result);
            return result;
        }
        private string BuscarCampoTipo(string Proyecto) {
            string result = "";

            if (Proyecto.Contains(C_DIP_TOKEN2) && Proyecto.Contains(C_DIP_TOKEN3)) {
                Proyecto = Proyecto.Substring(Proyecto.IndexOf(C_DIP_TOKEN2)); //+1
                Proyecto = Proyecto.Replace(C_DIP_TOKEN2, "");
                result = Proyecto.Substring(0, Proyecto.IndexOf(C_DIP_TOKEN3)).Trim();
            }

            return result;
        }
        private string BuscarCampoTexto(string Proyecto) {
            string result = "";

            if (Proyecto.Contains(C_DIP_TOKEN3) && Proyecto.Contains(C_DIP_TOKEN5)) { //C_DIP_TOKEN4
                Proyecto = Proyecto.Substring(Proyecto.IndexOf(C_DIP_TOKEN3)); //+1
                Proyecto = Proyecto.Replace(C_DIP_TOKEN3, "");

                result = Proyecto.Substring(0, Proyecto.IndexOf(C_DIP_TOKEN5)).Trim();
                result = StripHTMLTags(result);

                result = Regex.Replace(result, C_DIP_REGEX2, string.Empty);
                
                if (result.EndsWith("(")) result = result.Substring(0, result.Length - 1).Trim();
                if (!result.EndsWith(".")) result = result + ".";
            }

            return result;
        }
        private string BuscarCampoLink(string Proyecto) {
            string result = "";

            if (Proyecto.Contains(C_DIP_TOKEN5)) {
                if (!Proyecto.Contains(C_DIP_TOKEN6) && !Proyecto.Contains(C_DIP_TOKEN6Bis)) {
                    // Links en formato nuevo
                    Proyecto = Proyecto.Substring(Proyecto.IndexOf(C_DIP_TOKEN7)); // +1
                    Proyecto = Proyecto.Replace(C_DIP_TOKEN7, "");
                    result = C_DIP_URLINISLASH + Proyecto.Substring(0, Proyecto.IndexOf(C_DIP_TOKEN8)).Trim();
                }
            }

            if (string.IsNullOrEmpty(result)) {
                // Buscar con regex y armar el link
                Regex rSearch = new Regex(C_DIP_REGEX1, RegexOptions.IgnoreCase | RegexOptions.Singleline);
                Match mResult = rSearch.Match(Proyecto);
                if (mResult.Success) {
                    result = C_DIP_URLINISLASH + C_DIP_URLMID + mResult.Value.ToString();
                }
            }

            
            if (result.Contains(C_DIP_URLMID.ToUpper()))
                result = result.Replace(C_DIP_URLMID.ToUpper(), C_DIP_URLMID);

            return result;
        }
        private string BuscarCampoTags(string Proyecto) {
            string result = "";

            if (Proyecto.Contains(C_DIP_TOKEN9) && Proyecto.Contains(C_DIP_TOKEN1)) {
                Proyecto = Proyecto.Substring(Proyecto.IndexOf(C_DIP_TOKEN9));
                Proyecto = Proyecto.Replace(C_DIP_TOKEN9, "");
                result = Proyecto.Substring(0, Proyecto.IndexOf(C_DIP_TOKEN1)).Trim();
                result = result.Replace(" / ", ";").Replace("...", "");
            }
            return result;
        }


        // Proceso los proyectos de diputados segun las reglas que impuso /u/analia_vu
        private async void btnDipProcesarResultados_Click(object sender, RoutedEventArgs e) {
            SetControls(false);

            // Nombres en formato NOMBRE APELLIDO
            LogLine("Procesando proyectos de diputados - Nombres");
            ListaDipProyectos = await ProcesarNombres(ListaDipProyectos);

            // Texto en minusculas
            LogLine("Procesando proyectos de diputados - Minusculas");
            ListaDipProyectos = await ProcesarTextoMinusculas(ListaDipProyectos);

            // Otras cosas
            LogLine("Procesando proyectos de diputados - Correciones de formato");
            ListaDipProyectos = await ProcesarOtros(ListaDipProyectos);

            // Correccion de errores
            LogLine("Procesando proyectos de diputados - Correccion de errores");
            ListaDipProyectos = await ProcesarCorrecionErrores(ListaDipProyectos);

            LogLine("Fin del proceso de proyectos de diputados.");
            SetControls();
        }


        // Regla 1 - Nombres en formato Nombre Apellido 
        private async Task<List<CLS_DATA>> ProcesarNombres(List<CLS_DATA> Lista) {
            // EJ: 
            // ALEGRE, GILBERTO OSCAR; ALONSO, HORACIO FERNANDO; SELVA, CARLOS AMERICO; SNOPEK, ALEJANDRO FRANCISCO Y LAGORIA, ELIA NELLY
            // Gilberto Alegre, Horacio Alonso, Elia Lagoria, Carlos Selva y Alejandro Snopek

            //List<CLS_DATA> TempLista = Lista;

            ////TempLista.ForEach(z => { z.Representantes = ProcesarRepresentantes(z.Representantes); });
            //await Task.Run(() => { TempLista.ForEach(z => { z.Representantes = ProcesarRepresentantes(z.Representantes); }); });

            List<CLS_DATA> TempLista = new List<CLS_DATA>();

            await Task.Run(() => {
                foreach (CLS_DATA SingleItem in Lista) {
                    bool esMujer = true;

                    CLS_DATA TempItem = SingleItem;
                    TempItem.Representantes = ProcesarRepresentantes(TempItem.Representantes, ref esMujer);
                    TempItem.EsMujer = esMujer;

                    TempLista.Add(TempItem);
                }
            });

            //foreach(CLS_DATA SingleItem in Lista) {
            //    bool esMujer = true;

            //    CLS_DATA TempItem = SingleItem;
            //    TempItem.Representantes = ProcesarRepresentantes(TempItem.Representantes, ref esMujer);
            //    TempItem.EsMujer = esMujer;

            //    TempLista.Add(TempItem);
            //}

            return TempLista;
        }
        // Arma el nombre y chequea el genero
        private string ProcesarRepresentantes(string Representantes, ref bool esMujer) {
            string result = "";

            if (Representantes.Contains(C_DIP_SEPNOMBRE1) || Representantes.Contains(C_DIP_SEPNOMBRE2) || Representantes.Contains(C_DIP_SEPNOMBRE3)) {
                Representantes = Representantes.Replace(C_DIP_SEPNOMBRE2, C_DIP_SEPNOMBRE1);
                Representantes = Representantes.Replace(C_DIP_SEPNOMBRE3, C_DIP_SEPNOMBRE1);
                List<string> ListaRepresentantes = Representantes.Split(new string[] { C_DIP_SEPNOMBRE1 }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
                ListaRepresentantes.Sort();
                foreach (string Representante in ListaRepresentantes) {
                    string tempRep = InvertirNombre(Representante);
                    result = result + tempRep + ", ";

                    if (!Mujeres.Contains(tempRep)) esMujer = false;
                }

                result = result.Substring(0, result.Length - 2); // Sobra ultima coma
                result = ReplaceLastOccurrence(result, ",", " y");
            }
            else {
                result = InvertirNombre(Representantes);
                if (!Mujeres.Contains(result)) esMujer = false;
            }
            return result;
        }
        // Deja un nombre en formato Nombre Apellido
        private string InvertirNombre(string Nombre) {
            // EJ: 
            // CREMER DE BUSTI, MARIA CRISTINA
            // Maria Cremer De Busti
            if (Nombre.Contains(",")) {
                string[] Nombres = Nombre.Split(',');
                string[] Subnombres = Nombres[1].Trim().Split(' ');
                Nombre = Subnombres[0] + " " + Nombres[0].Trim();
                Nombre = new System.Globalization.CultureInfo("en-US").TextInfo.ToTitleCase(Nombre.ToLower());
            }
            return Nombre;
        }

        //private string ProcesarRepresentantes(string Representantes) {
        //    string result = "";

        //    if (Representantes.Contains(C_DIP_SEPNOMBRE1) || Representantes.Contains(C_DIP_SEPNOMBRE2) || Representantes.Contains(C_DIP_SEPNOMBRE3)) {
        //        Representantes = Representantes.Replace(C_DIP_SEPNOMBRE2, C_DIP_SEPNOMBRE1);
        //        Representantes = Representantes.Replace(C_DIP_SEPNOMBRE3, C_DIP_SEPNOMBRE1);
        //        List<string> ListaRepresentantes = Representantes.Split(new string[] { C_DIP_SEPNOMBRE1 }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
        //        ListaRepresentantes.Sort();
        //        foreach (string Representante in ListaRepresentantes)
        //            result = result + InvertirNombre(Representante) + ", ";

        //        result = result.Substring(0, result.Length - 2); // Sobra ultima coma
        //        result = ReplaceLastOccurrence(result, ",", " y");
        //    }
        //    else {
        //        result = InvertirNombre(Representantes);
        //    }
        //    return result;
        //}


        // Regla 2 - Texto en minusculas
        private async Task<List<CLS_DATA>> ProcesarTextoMinusculas(List<CLS_DATA> Lista) {
            List<CLS_DATA> TempLista = Lista;

            //TempLista.ForEach(z => { z.Texto = z.Texto.ToLower(); });
            await Task.Run(() => { TempLista.ForEach(z => { z.Texto = z.Texto.ToLower(); }); });

            return TempLista;
        }

        // Regla 3 - Correccion de errores
        private async Task<List<CLS_DATA>> ProcesarCorrecionErrores(List<CLS_DATA> Lista) {
            List<CLS_DATA> TempLista = Lista;

            await Task.Run(() => { TempLista.ForEach(z => { z.Texto = CorregirTexto(z.Texto); }); });

            return TempLista;
        }
        // Corrige errores de un texto automáticamente.
        private string CorregirTexto(string Texto) {
            string result = "";

            Application.Current.Dispatcher.Invoke(delegate {
                TextBox txtCorreccion = new TextBox();
                txtCorreccion.Language = System.Windows.Markup.XmlLanguage.GetLanguage("es-AR");
                txtCorreccion.SpellCheck.IsEnabled = true;
                txtCorreccion.Text = Texto;

                int spellingErrorIndex = txtCorreccion.Text.Length;
                do {
                    SpellingError spellingError = txtCorreccion.GetSpellingError(spellingErrorIndex);

                    if (spellingError != null) {
                        IEnumerable<string> suggestions = spellingError.Suggestions;
                        if (Helper.IsAny<string>(suggestions)) {
                            spellingError.Correct(suggestions.First());
                        }
                    }

                    spellingErrorIndex = txtCorreccion.GetNextSpellingErrorCharacterIndex(spellingErrorIndex, LogicalDirection.Backward);
                } while (spellingErrorIndex >= 0);

                result = txtCorreccion.Text;
                txtCorreccion.Text = "";
            });

            return result;
        }

        // Regla 4 - Corrige detalles
        private async Task<List<CLS_DATA>> ProcesarOtros(List<CLS_DATA> Lista) {
            List<CLS_DATA> TempLista = Lista;

            await Task.Run(() => { TempLista.ForEach(z => { z.Texto = z.Texto.Replace("&deg;", "°").Replace("&quot;", "\""); }); });
            await Task.Run(() => { TempLista.ForEach(z => { z.Texto = RemoverEspaciosDobles(z.Texto); }); });

            return TempLista;
        }
        

        // Muestra los diputados y sus proyectos
        private void btnDipMostrarResultados_Click(object sender, RoutedEventArgs e) {
            string Prefijo_H = "", Prefijo_M = "", SufijoVarios = "", SufijoSimple = "", Texto = "";
            SetControls(false);
            LogLine("Mostrando los tramites parlamentarios de diputados...");

            List<string> Diputados = ListaDipProyectos.Select(d => d.Representantes).Distinct().ToList();
            foreach (string Diputado in Diputados) {
                List<CLS_DATA> ListaTemp = ListaDipProyectos.Where(w => w.Representantes == Diputado).ToList<CLS_DATA>();
                Paragraph parag = new Paragraph();

                if (Diputado.Contains(C_DIP_SEPNOMBRE4)) {
                    Prefijo_H = "Los diputados nacionales ";
                    Prefijo_M = "Las diputadas nacionales ";
                    SufijoVarios = " presentaron los siguientes proyectos:";
                    SufijoSimple = " presentaron el";
                }
                else {
                    Prefijo_H = "El diputado nacional ";
                    Prefijo_M = "La diputada nacional ";
                    SufijoVarios = " presentó los siguientes proyectos:";
                    SufijoSimple = " presentó el";
                }

                if (ListaTemp.Count() > 1) {
                    //"<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES#:</p>\r\n<ul>\r\n#LIDATA#</ul>\r\n";
                    Texto = C_TEMPLATE_MULTIPLE;

                    if (ListaTemp[0].EsMujer)
                        Texto = Texto.Replace("#REPRESENTANTES#", Prefijo_M + ListaTemp[0].Representantes + SufijoVarios);
                    else
                        Texto = Texto.Replace("#REPRESENTANTES#", Prefijo_H + ListaTemp[0].Representantes + SufijoVarios);

                    string Linea = "", Lineas = "";
                    foreach (CLS_DATA Proyecto in ListaTemp) {
                        //"<li style=\"text-align:justify;\"><a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</li>\r\n";
                        Linea = C_TEMPLATE_MULTIPLE_LINEA;
                        Linea = Linea.Replace("#LINK#", Proyecto.Link);
                        Linea = Linea.Replace("#LINKTITULO#", "Proyecto " + Proyecto.Tipo.ToLower());
                        Linea = Linea.Replace("#PROYECTO#", Proyecto.Texto);
                        Lineas = Lineas + Linea;
                    }
                    Texto = Texto.Replace("#LIDATA#", Lineas);
                    txtHTMLResult.Text = txtHTMLResult.Text + Texto;
                }
                else { // Un solo proyecto
                    //"<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES# <a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</p>\r\n";
                    Texto = C_TEMPLATE_SIMPLE;
                    if (ListaTemp[0].EsMujer) 
                        Texto = Texto.Replace("#REPRESENTANTES#", Prefijo_M + ListaTemp[0].Representantes + SufijoSimple);
                    else
                        Texto = Texto.Replace("#REPRESENTANTES#", Prefijo_H + ListaTemp[0].Representantes + SufijoSimple);

                    Texto = Texto.Replace("#LINK#", ListaTemp[0].Link);
                    Texto = Texto.Replace("#LINKTITULO#", "proyecto " + ListaTemp[0].Tipo.ToLower());
                    Texto = Texto.Replace("#PROYECTO#", ListaTemp[0].Texto);

                    txtHTMLResult.Text = txtHTMLResult.Text + Texto;
                }
            }
            LogLine("Fin!");
            SetControls();
        }


        // Agrega una linea de texto al log
        private void LogLine(string txt, bool CRLF = true) {
            Application.Current.Dispatcher.Invoke(delegate {
                if (CRLF)
                    txtLog.Text = txtLog.Text + txt + "\r\n";
                else
                    txtLog.Text = txtLog.Text + txt;
                txtLog.ScrollToEnd();
            });
        }

        // Obtiene el codigo de una pagina web
        private async Task<string> GetWeb(string URL) {
            string Result = "";

            try {
                using (System.Net.WebClient objClient = new System.Net.WebClient()) {
                    if (!string.IsNullOrEmpty(C_PROXY)) {
                        WebProxy Prx = new WebProxy(C_PROXY, true);
                        Prx.UseDefaultCredentials = true;
                        objClient.Proxy = Prx;
                    }
                    objClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);

                    byte[] ReturnValue = { };
                    await Task.Run(() => { ReturnValue = objClient.DownloadData(URL); });
                    //await
                    //byte[] ReturnValue = objClient.DownloadData(URL); 
                    System.Text.UTF8Encoding Encoder = new System.Text.UTF8Encoding();
                    Result = Encoder.GetString(ReturnValue);
                }
            }
            catch (Exception EX) {
                Result = "";
                LogLine("[ERROR] [GetWeb]: " + URL + " > " + EX.Message);
            }
            return Result;
        }

        //***** Eliminar en version final 
        // Obtiene el codigo de una pagina web
        private string GetWebSync(string URL) {
            string Result = "";

            try {
                using (System.Net.WebClient objClient = new System.Net.WebClient()) {
                    if (!string.IsNullOrEmpty(C_PROXY)) {
                        WebProxy Prx = new WebProxy(C_PROXY, true);
                        Prx.UseDefaultCredentials = true;
                        objClient.Proxy = Prx;
                    }
                    objClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
                    byte[] ReturnValue = objClient.DownloadData(URL);
                    System.Text.UTF8Encoding Encoder = new System.Text.UTF8Encoding();
                    Result = Encoder.GetString(ReturnValue);
                }
            }
            catch (Exception EX) {
                Result = "";
                LogLine("[ERROR] [GetWeb]: " + URL + " > " + EX.Message);
            }
            return Result;
        }

        // Cambia la ultima ocurrencia de un string
        private string ReplaceLastOccurrence(string Source, string Find, string Replace) {
            int place = Source.LastIndexOf(Find);

            if (place == -1) return Source;

            string result = Source.Remove(place, Find.Length).Insert(place, Replace);
            return result;
        }

        // Elimina tags html
        private string StripHTMLTags(string Source) {
            return Regex.Replace(Source, "<.*?>", string.Empty);
        }

        // Bloquea controles
        private void SetControls(bool isEnabled = true) {
            dtpFechaDesde.IsEnabled = isEnabled;
            dtpFechaHasta.IsEnabled = isEnabled;

            btnDipBuscarTramites.IsEnabled = isEnabled;
            btnDipProcesarResultados.IsEnabled = isEnabled;
            btnDipMostrarResultados.IsEnabled = isEnabled;

            btnDipBuscarComisiones.IsEnabled = isEnabled;
            btnDipMostrarComisiones.IsEnabled = isEnabled;

            btnSenBuscarTramites.IsEnabled = isEnabled;
            btnSenProcesarResultados.IsEnabled = isEnabled;
            btnSenMostrarResultados.IsEnabled = isEnabled;
        }

        // Verifica que el usuario haya seleccionado una fecha y al menos un tipo de proyecto
        private bool OptionsOK() {
            bool result = true;
            string msg = "";

            // Fechas
            if (!dtpFechaDesde.SelectedDate.HasValue || !dtpFechaHasta.SelectedDate.HasValue) {
                msg = "Seleccione un rango de fechas!";
                result = false;
            }

            if (!chkProyectoLey.IsChecked.Value && 
                !chkProyectoComunicacion.IsChecked.Value && 
                !chkProyectoDeclaracion.IsChecked.Value && 
                !chkProyectoReproduccion.IsChecked.Value && 
                !chkProyectoResolucion.IsChecked.Value) {

                result = false;
                if (string.IsNullOrEmpty(msg))
                    msg = "Seleccione al menos un tipo de proyecto";
                else
                    msg = msg + "\r\nSeleccione al menos un tipo de proyecto";
            }

            if (!result) {
                MessageBox.Show(msg);
                SetControls();
            }

            return result;
        }

        // Elimina los dobles espacios
        private string RemoverEspaciosDobles(string Texto) {
            string result = "";

            RegexOptions options = RegexOptions.None;
            Regex regex = new Regex("[ ]{2,}", options);
            result = regex.Replace(Texto, " ");

            return result;
        }

        // Priemra letra en mayusculas, estilo oracion
        private string PrimeraLetraMayus(string Texto) {
            return char.ToUpper(Texto[0]) + Texto.Substring(1).ToLower();
        }


        // Busca las reuniones de comisiones de diputados
        private async void btnDipBuscarComisiones_Click(object sender, RoutedEventArgs e) {
            SetControls(false);

            // Fechas
            if (!dtpFechaDesde.SelectedDate.HasValue || !dtpFechaHasta.SelectedDate.HasValue) {
                MessageBox.Show("Seleccione un rango de fechas!");
                SetControls();
                return;
            }

            LogLine("Cargando el sitio " + txtDipUrlComisiones.Text);
            string strReuniones = await GetWeb(txtDipUrlComisiones.Text);

            if (!string.IsNullOrEmpty(strReuniones)) {
                LogLine("Sitio cargado. Buscando reuniones en el rango de fechas [" +
                    dtpFechaDesde.SelectedDate.Value.ToString("dd-MM-yyyy") + " - " +
                    dtpFechaHasta.SelectedDate.Value.ToString("dd-MM-yyyy") + "]");

                HtmlAgilityPack.HtmlDocument objDoc = new HtmlAgilityPack.HtmlDocument();
                objDoc.LoadHtml(strReuniones);

                if (objDoc.DocumentNode != null) {
                    // Hay varias tablas, una por cada fecha.
                    // <table  id="agendaComisiones" width="90%"  class="table table-bordered" cellspacing="5"  ><thead><tr><th align='center' colspan=2 >REUNIONES DEL DIA 23/03/2017</th></tr></thead>
                    ListaDipComisiones.Clear();
                    HtmlNodeCollection Tablas = objDoc.DocumentNode.SelectNodes("//table");
                    foreach (HtmlNode TablaReunion in Tablas) {
                        HtmlNode NodeTitulo = TablaReunion.SelectSingleNode(".//thead");
                        string[] strFechaReunion = NodeTitulo.InnerText.Replace(C_COM_TITLE, "").Split('/');
                        DateTime FechaReunion = new DateTime(int.Parse(strFechaReunion[2]), int.Parse(strFechaReunion[1]), int.Parse(strFechaReunion[0]));
                        if (FechaReunion.Ticks >= dtpFechaDesde.SelectedDate.Value.Ticks && FechaReunion.Ticks <= dtpFechaHasta.SelectedDate.Value.Ticks) {
                            BuscarComisiones(TablaReunion, FechaReunion);
                        }
                    }
                }
                else {
                    LogLine("[ERROR] [btnDipBuscarComisiones_Click]: objDoc.DocumentNode == null");
                }
                LogLine("Busquedad de reuniones de comisiones finalizada!");
            }
            else {
                LogLine("Hubo un error cargando el sitio. Reintente nuevamente.");
            }
            SetControls();
        }
     
        // Busca la info de cada reunion
        private void BuscarComisiones(HtmlNode NodeTabla, DateTime Fecha) {

            HtmlNodeCollection Filas = NodeTabla.SelectNodes(".//td");
            foreach (HtmlNode Fila in Filas) {
                if (Fila.InnerHtml.Contains(C_COM_TOKEN1)) {
                    CLS_DATA Reunion = new CLS_DATA();
                    HtmlNode Vinculo = Fila.SelectSingleNode(".//a");

                    // Fecha
                    Reunion.Fecha = Fecha;

                    // Link
                    Reunion.Link = C_DIP_URLINI + Vinculo.Attributes["href"].Value;

                    // Comisiones
                    Reunion.Representantes = Vinculo.InnerText.ToLower().Replace(C_COM_SEARCH1, "").Replace(C_COM_SEARCH2, "").Trim();
                    Reunion.Representantes = new System.Globalization.CultureInfo("en-US").TextInfo.ToTitleCase(Reunion.Representantes);
                    // Articulos y otros en minuscula
                    foreach (string Articulo in C_COM_WORDS1) {
                        Reunion.Representantes = Reunion.Representantes.Replace(Articulo, Articulo.ToLower());
                    }

                    // Texto
                    Reunion.Texto = Fila.InnerHtml;
                    Reunion.Texto = Reunion.Texto.Replace("\r", "").Replace("\n", "");
                    if (Reunion.Texto.Contains(C_COM_TOKEN2))
                        Reunion.Texto = Reunion.Texto.Substring(Reunion.Texto.IndexOf(C_COM_TOKEN2) + C_COM_TOKEN2.Length);
                    else
                        Reunion.Texto = Reunion.Texto.Substring(Reunion.Texto.IndexOf(C_COM_TOKEN3) + C_COM_TOKEN3.Length);
                    // espacios dobles
                    while (Reunion.Texto.Contains("  ")) {
                        Reunion.Texto = Reunion.Texto.Replace("  ", " ");
                    }
                    Reunion.Texto = Reunion.Texto.Trim();

                    ListaDipComisiones.Add(Reunion);
                }
            }
        }

        // Muestra las reuniones de comisiones
        private void btnDipMostrarComisiones_Click(object sender, RoutedEventArgs e) {
            SetControls(false);
            LogLine("Mostrando las comisiones de diputados...");
            string texto = "";

            foreach (CLS_DATA Reunion in ListaDipComisiones) {
                if (Reunion.Representantes.Contains(";")) {
                    texto = "<p style=\"text-align:justify;\" align=\"justify\">Se reunieron";

                    texto = texto + " en diputados ";
                }
                else {
                    texto = "<p style=\"text-align:justify;\" align=\"justify\">Se reunió la comisión de " + Reunion.Representantes + " en diputados ";
                }

                // En palabras del gran Tusam, puede fallar :D ... fucking puntos.
                // ***** algun dia se haran las excepciones correspondientes
                List<string> Temas = Reunion.Texto.Split(new string[] { ". " }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
                if (Temas.Count > 1) {
                    texto = texto + "para tratar los siguientes temas:</p>\r\n<ul>\r\n";
                    string TempTema = "";
                    foreach (string Tema in Temas) {
                        TempTema = Tema;
                        if (!TempTema.EndsWith(".")) TempTema = TempTema + ".";
                        texto = texto + "<li style=\"text-align:justify;\">" + TempTema + "</li>\r\n";
                    }
                    texto = texto + "</ul>\r\n";
                }
                else {
                    texto = texto + "para " + Temas[0] + "</p>\r\n";
                }
                txtHTMLResult.Text = txtHTMLResult.Text + texto;
            }
            LogLine("Fin!");
            SetControls();
        }


        // Busca los proyectos presentados por cada senador
        private async void btnSenBuscarTramites_Click(object sender, RoutedEventArgs e) {
            SetControls(false);

            // Opciones
            if (!OptionsOK()) return;

            LogLine("Cargando el sitio " + txtSenUrlTramites.Text);
            string strTramites = await GetWeb(txtSenUrlTramites.Text);
            //string strTramites = GetWebSync(txtSenUrlTramites.Text);

            if (!string.IsNullOrEmpty(strTramites)) {
                LogLine("Sitio cargado. Buscando senadores, hagase de paciencia...");

                HtmlAgilityPack.HtmlDocument objDoc = new HtmlAgilityPack.HtmlDocument();
                objDoc.LoadHtml(strTramites);

                if (objDoc.DocumentNode != null) {
                    // Tablas - Hay una sola, es la que me interesa :D
                    HtmlNodeCollection Tables = objDoc.DocumentNode.SelectNodes("//table");
                    HtmlNode TableTramites = Tables[0];

                    // Los senadores
                    HtmlNodeCollection NodeCols = TableTramites.SelectNodes(".//td");

                    foreach (HtmlNode NodeC in NodeCols) {
                        if (NodeC.InnerHtml.Contains(C_SEN_TOKEN1) && !NodeC.InnerHtml.Contains(C_SEN_TOKEN2) && !NodeC.InnerHtml.Contains(C_SEN_TOKEN3)) {
                            HtmlNode SingleNode = NodeC.SelectSingleNode(".//a");
                            string Senador = SingleNode.Attributes["title"].Value;
                            Senador = new System.Globalization.CultureInfo("en-US").TextInfo.ToTitleCase(Senador.ToLower());
                            string Link = C_SEN_URLINI + SingleNode.Attributes["href"].Value + C_SEN_URLEND;
                            LogLine(Senador + ": ", false);

                            List<CLS_DATA> ListaTemp = await BuscarSenProyectos(Link);
                            await Task.Run(() => {
                                if (ListaTemp != null && ListaTemp.Count > 0) ListaSenProyectos.AddRange(ListaTemp);
                                LogLine(ListaTemp.Count.ToString() + " proyectos encontrados");
                            });
                        }
                    }
                }
                else {
                    LogLine("[ERROR] [btnSenBuscarTramites_Click]: objDoc.DocumentNode == null");
                }
                LogLine("Busquedad de tramites parlamentarios de senadores finalizada!");
            }
            else {
                LogLine("Hubo un error cargando el sitio. Reintente nuevamente.");
            }
            SetControls();
        }

        // Busca los proyectos de cada senador en particular
        private async Task<List<CLS_DATA>> BuscarSenProyectos(string URLProyecto) {
            List<CLS_DATA> ListaProyectos = new List<CLS_DATA>();
            int NroPagina = 1;
            bool SeguirBuscando = true;
            string Representante = "", URLActual = ""; ;

            while (SeguirBuscando) {
                URLActual = URLProyecto.Replace("#NRO#", NroPagina.ToString());
                //string strProyectos = GetWebSync(URLActual);
                string strProyectos = await GetWeb(URLActual);

                if (!string.IsNullOrEmpty(strProyectos)) {
                    //LogLine("Pagina " + NroPagina.ToString() + "...");
                    HtmlAgilityPack.HtmlDocument objDoc = new HtmlAgilityPack.HtmlDocument();
                    objDoc.LoadHtml(strProyectos);

                    if (objDoc.DocumentNode != null) {
                        // En la primera pagina busco el nombre
                        if (string.IsNullOrEmpty(Representante))
                            Representante = await BuscarSenador(objDoc);

                        // Tablas - Hay dos, me interesa la primera
                        HtmlNodeCollection Tables = objDoc.DocumentNode.SelectNodes("//table");
                        HtmlNode TableTramites = Tables[0];
                        List<CLS_DATA> ListaTemp = ParsearTablaSenador(TableTramites, Representante, ref SeguirBuscando);
                        if (ListaTemp != null && ListaTemp.Count > 0) ListaProyectos.AddRange(ListaTemp);
                        if (!SeguirBuscando) return ListaProyectos;
                    }
                    else {
                        LogLine("[ERROR] [btnSenBuscarTramites_Click]: objDoc.DocumentNode == null");
                        SeguirBuscando = false;
                    }
                }
                else {
                    LogLine("Hubo un error cargando el sitio. Reintente nuevamente.");
                    SeguirBuscando = false;
                }
                NroPagina++;
            }
            return ListaProyectos;
        }

        // Busca el nombre y apellido de un senador
        private async Task<string> BuscarSenador(HtmlDocument objDoc) {
            string Apellido = "", Nombre = "", result = "";
            await Task.Run(() => {
                // Apellido
                HtmlNode NodeDiv = objDoc.DocumentNode.Descendants("div").Where(w => (w.Attributes["style"] != null && w.Attributes["style"].Value.Contains(C_SEN_TOKEN6_class))).Single();
                HtmlNode NodeSpan = NodeDiv.SelectSingleNode(".//span");
                Apellido = NodeSpan.InnerText.Trim();
                // Nombre
                NodeDiv.RemoveChild(NodeSpan);
                Nombre = NodeDiv.InnerText.Trim();
                if (Nombre.Contains(" ")) Nombre = Nombre.Substring(0, Nombre.IndexOf(" "));

                result = Nombre + " " + Apellido;
            } );

            return result;
        }

        // Parsea la tabla de proyectos
        private List<CLS_DATA> ParsearTablaSenador(HtmlNode Tabla, string Representante, ref bool SeguirBuscando) {
            List<CLS_DATA> ListaProyectos = new List<CLS_DATA>();
            bool Procesar = false;

            // Columnas
            HtmlNodeCollection NodeRows = Tabla.SelectNodes(".//tr");
            foreach (HtmlNode NodeR in NodeRows) {
                CLS_DATA TempProyecto = new CLS_DATA();

                // Filas
                HtmlNodeCollection NodeCols = NodeR.SelectNodes(".//td");
                if (NodeCols != null) {
                    
                    // Fecha
                    string[] strFechaProyecto = NodeCols[1].InnerText.Trim().Split('-');
                    TempProyecto.Fecha = new DateTime(int.Parse(strFechaProyecto[2]), int.Parse(strFechaProyecto[1]), int.Parse(strFechaProyecto[0]));

                    if (TempProyecto.Fecha.Ticks >= dtpFechaDesde.SelectedDate.Value.Ticks && TempProyecto.Fecha.Ticks <= dtpFechaHasta.SelectedDate.Value.Ticks) {
                        // Proyecto
                        Procesar = false;
                        TempProyecto.Texto = RemoverEspaciosDobles(NodeCols[2].InnerText);

                        if (chkProyectoComunicacion.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_COMUNICACION)) {
                            TempProyecto.Tipo = C_SEN_PROYECTO_COMUNICACION;
                            Procesar = true;
                        }
                        if (chkProyectoDeclaracion.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_DECLARACION)) {
                            TempProyecto.Tipo = C_SEN_PROYECTO_DECLARACION;
                            Procesar = true;
                        }
                        if (chkProyectoResolucion.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_RESOLUCION)) {
                            TempProyecto.Tipo = C_SEN_PROYECTO_RESOLUCION;
                            Procesar = true;
                        }
                        if (chkProyectoLey.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_LEY)) {
                            TempProyecto.Tipo = C_SEN_PROYECTO_LEY;
                            Procesar = true;
                        }

                        if (chkProyectoReproduccion.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_REPRODUCCION)) {
                            TempProyecto.Tipo = "Proyecto de reproducción";
                            Procesar = true;
                        }
                        else if (!chkProyectoReproduccion.IsChecked.Value && TempProyecto.Texto.Contains(C_SEN_PROYECTO_REPRODUCCION))
                            Procesar = false;

                        if (Procesar) {
                            // Tipo
                            TempProyecto.Tipo = TempProyecto.Tipo.Replace("cion", "ción");
                            // Mas proyecto
                            TempProyecto.Texto = NodeCols[2].InnerText.Substring(NodeCols[2].InnerText.IndexOf(C_SEN_TOKEN5) + C_SEN_TOKEN5.Length);
                            TempProyecto.Texto = TempProyecto.Texto.Trim().ToLower();
                            TempProyecto.Texto = TempProyecto.Texto.ToLower().Replace(TempProyecto.Tipo.ToLower(), "");
                            TempProyecto.Texto = RemoverEspaciosDobles(TempProyecto.Texto).Trim();
                            if (!TempProyecto.Texto.EndsWith(".")) TempProyecto.Texto = TempProyecto.Texto + ".";

                            // Chango
                            TempProyecto.Representantes = Representante;
                            // Genero
                            if (Mujeres.Contains(TempProyecto.Representantes))
                                TempProyecto.EsMujer = true;
                            else
                                TempProyecto.EsMujer = false;

                            // Link
                            HtmlNode NodeLink = NodeCols[0].SelectSingleNode(".//a");
                            TempProyecto.Link = C_SEN_URLINI + NodeLink.Attributes["href"].Value;

                            ListaProyectos.Add(TempProyecto);
                        }
                    }
                    else if (TempProyecto.Fecha.Ticks < dtpFechaDesde.SelectedDate.Value.Ticks) {
                        SeguirBuscando = false;
                        return ListaProyectos;
                    }
                }
            }
            return ListaProyectos;
        }


        // Proceso los proyectos de senadores segun las reglas que impuso /u/analia_vu
        private async void btnSenProcesarResultados_Click(object sender, RoutedEventArgs e) {
            SetControls(false);

            // Nombres en formato NOMBRE APELLIDO
            // EL parser ya los saca en ese formato

            // Texto en minusculas
            // EL parser ya los saca en minusculas

            // Otras cosas
            LogLine("Procesando proyectos de senadores - Correcciones de formato");
            ListaSenProyectos = await ProcesarOtros(ListaSenProyectos);

            // Correccion de errores
            LogLine("Procesando proyectos de senadores - Correccion de errores");
            ListaSenProyectos = await ProcesarCorrecionErrores(ListaSenProyectos);

            LogLine("Fin del proceso de proyectos de senadores.");
            SetControls();
        }

        // Muestra los proyectos de senadores
        private void btnSenMostrarResultados_Click(object sender, RoutedEventArgs e) {
            SetControls(false);
            LogLine("Mostrando los tramites parlamentarios de senadores...");
            string Texto = "";

            // Primero junto a todos los senadores que publicaron el mismo proyecto
            List<string> Links = ListaSenProyectos.Select(s => s.Link).Distinct().ToList();
            foreach (string Link in Links) {
                List<CLS_DATA> ListaTemp = ListaSenProyectos.Where(w => w.Link == Link).ToList();

                if (ListaTemp.Count > 1) {
                    string Representantes = "";
                    bool esMujer = true;
                    foreach(CLS_DATA Temp in ListaTemp) {
                        if (!Temp.EsMujer) esMujer = false;
                        Representantes = Representantes + Temp.Representantes + ", ";
                    }
                    Representantes = Representantes.Substring(0, Representantes.Length - 2); // Sobra ultima coma
                    Representantes = ReplaceLastOccurrence(Representantes, ",", " y");

                    //"<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES# <a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</p>\r\n";
                    Texto = C_TEMPLATE_SIMPLE;
                    if (ListaTemp[0].EsMujer)
                        Texto = Texto.Replace("#REPRESENTANTES#", "Las senadoras nacionales " + Representantes + " presentaron");
                    else
                        Texto = Texto.Replace("#REPRESENTANTES#", "Los senadores nacionales " + Representantes + " presentaron");

                    Texto = Texto.Replace("#LINK#", ListaTemp[0].Link);
                    Texto = Texto.Replace("#LINKTITULO#", ListaTemp[0].Tipo.ToLower());
                    Texto = Texto.Replace("#PROYECTO#", ListaTemp[0].Texto);

                    txtHTMLResult.Text = txtHTMLResult.Text + Texto;
                    ListaSenProyectos = ListaSenProyectos.Where(w => w.Link != Link).ToList();
                }
            }

            List<string> Senadores = ListaSenProyectos.Select(s => s.Representantes).Distinct().ToList();
            foreach(string Senador in Senadores) {
                List<CLS_DATA> ListaTemp = ListaSenProyectos.Where(w => w.Representantes == Senador).ToList();

                Paragraph parag = new Paragraph();
                if (ListaTemp.Count == 1) {  // Un solo proyecto
                    //"<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES# <a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</p>\r\n";
                    Texto = C_TEMPLATE_SIMPLE;
                    if (ListaTemp[0].EsMujer)
                        Texto = Texto.Replace("#REPRESENTANTES#", "La senadora nacional " + Senador + " presentó");
                    else
                        Texto = Texto.Replace("#REPRESENTANTES#", "El senador nacional " + Senador + " presentó");

                    Texto = Texto.Replace("#LINK#", ListaTemp[0].Link);
                    Texto = Texto.Replace("#LINKTITULO#", ListaTemp[0].Tipo.ToLower());
                    Texto = Texto.Replace("#PROYECTO#", ListaTemp[0].Texto);
                }
                else {
                    //"<p style=\"text-align:justify;\" align=\"justify\">#REPRESENTANTES#:</p>\r\n<ul>\r\n#LIDATA#</ul>\r\n";
                    Texto = C_TEMPLATE_MULTIPLE;
                    if (ListaTemp[0].EsMujer)
                        Texto = Texto.Replace("#REPRESENTANTES#", "La senadora nacional " + Senador + " presentó los siguientes proyectos:");
                    else
                        Texto = Texto.Replace("#REPRESENTANTES#", "El senador nacional " + Senador + " presentó los siguientes proyectos:");

                    string Linea = "", Lineas = "";
                    foreach (CLS_DATA Proyecto in ListaTemp) {
                        //"<li style=\"text-align:justify;\"><a href=\"#LINK#\">#LINKTITULO#</a> #PROYECTO#</li>\r\n";
                        Linea = C_TEMPLATE_MULTIPLE_LINEA;
                        Linea = Linea.Replace("#LINK#", Proyecto.Link);
                        Linea = Linea.Replace("#LINKTITULO#", PrimeraLetraMayus(Proyecto.Tipo));
                        Linea = Linea.Replace("#PROYECTO#", Proyecto.Texto);
                        Lineas = Lineas + Linea;
                    }
                    Texto = Texto.Replace("#LIDATA#", Lineas);
                }
                txtHTMLResult.Text = txtHTMLResult.Text + Texto;
            }
            LogLine("Fin!");
            SetControls();
        }
    }

    public static class Helper {
        public static bool IsAny<T>(this IEnumerable<T> data) {
            return data != null && data.Any();
        }
    }
}